package org.boot.fast.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.boot.fast.properties.FastFilePropertiesConfiguration;
import org.boot.fast.mapp.MimeMapping;
import org.boot.fast.pojo.FileInfoDO;
import org.boot.fast.dao.FileInfoDAO;
import org.boot.fast.service.FileUploadService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Slf4j
@Service
public class FileUploadServiceImpl implements FileUploadService {

    @Resource
    private FastFilePropertiesConfiguration fileStorageConfig;

    @Resource
    private FileInfoDAO fileInfoRepository;

    @Override
    public FileInfoDO upload(MultipartFile file, String uploadUser) {
        String fileKey = uuid();
        String fileType = type(file);

        Path path = Paths.get(fileStorageConfig.getFilePath() + "/" + fileKey + fileType);

        FileInfoDO fileInfo = new FileInfoDO(file.getOriginalFilename(), path.toString().replace('\\', '/'), file.getSize(), fileType, fileKey);
        fileInfo.setUploadUser(Optional.ofNullable(uploadUser).orElse("unknown"));
        fileInfo.setUploadTime(LocalDateTime.now());
        try{
            Files.write(path, file.getBytes());
            fileInfo.setId(fileInfoRepository.save(fileInfo));
        } catch (Exception e) {
            log.error("上传文件失败", e);
            throw new RuntimeException(e);
        }
        return fileInfo;
    }

    @Override
    public List<Long> uploadBatch(List<MultipartFile> files, String uploadUser) {
        List<Long> ids = new ArrayList<>(files.size());
        for (MultipartFile file : files) {
            if (file.isEmpty()) continue;          // 跳过空文件
            ids.add(upload(file, uploadUser).getId()); // 复用原来的单文件方法
        }
        return ids;
    }

    @Override
    public Boolean delete(Long id) {
        /* 1. 查数据库 */
        FileInfoDO fileInfo = fileInfoRepository.findOne(id);
        if (fileInfo == null) {
            throw new RuntimeException("文件记录不存在！");
        }
        /* 2. 拼物理路径并校验 */
        String rootPath = fileStorageConfig.getFilePath();
        if (rootPath == null || rootPath.trim().isEmpty()) {
            throw new RuntimeException("文件根路径未配置！");
        }
        Path path = Paths.get(fileInfo.getFilePath());
        try {
            /* 3. 先删磁盘 */
            if (Files.exists(path)) {
                Files.delete(path);
            }
            /* 4. 再删数据库 */
            fileInfoRepository.delete(id);
        } catch (IOException e) {
            throw new RuntimeException("删除磁盘文件失败", e);
        } catch (Exception e) {
            throw new RuntimeException("删除数据库记录失败", e);
        }
        return true;
    }

    @Override
    public void download(Long id, HttpServletResponse response) {
        FileInfoDO fileInfo = fileInfoRepository.findOne(id);
        if (fileInfo == null) {
            throw new RuntimeException("文件不存在！");
        }
        try{
            response.setContentType("application/force-download");// 设置强制下载不打开
            response.addHeader("Content-Disposition","attachment;fileName="
                    + new String(fileInfo.getFileName().getBytes("UTF-8"),"iso-8859-1"));

            // ------------------------------附件读取--------------------------------------------------
            String rootPath = fileStorageConfig.getFilePath();
            if (rootPath == null || rootPath.trim().isEmpty()) {
                throw new RuntimeException("文件根路径未配置！");
            }
            Path path = Paths.get(fileInfo.getFilePath());
            if (!Files.exists(path)) {
                throw new RuntimeException("文件物理路径不存在！");
            }
            //读取文件，获取byte[]
            byte[] bytes = Files.readAllBytes(path);
            response.getOutputStream().write(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void preview(Long id, HttpServletResponse response) {
        FileInfoDO fileInfo = fileInfoRepository.findOne(id);
        if (fileInfo == null) {
            throw new RuntimeException("文件不存在！");
        }

        String fileName = fileInfo.getFileName();
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        String mimeType = MimeMapping.getMimeType(suffix);   // 获取MIME类型
        if (mimeType == null) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            throw new RuntimeException("不支持的预览格式");
        }
        response.setContentType(mimeType);
        response.setCharacterEncoding("UTF-8");

        /* 2. 缓存控制，可按需调整 */
        response.setHeader("Cache-Control", "max-age=3600");

        /* 3. 输出文件流 */
        String rootPath = fileStorageConfig.getFilePath();
        if (rootPath == null || rootPath.trim().isEmpty()) {
            throw new RuntimeException("文件路径不存在！");
        }
        Path path = Paths.get(fileInfo.getFilePath());
        if (!Files.exists(path)) {
            throw new RuntimeException("文件物理路径不存在！");
        }

        try (ServletOutputStream out = response.getOutputStream()) {
            Files.copy(path, out);
            out.flush();
        } catch (IOException e) {
            throw new RuntimeException("预览文件失败", e);
        }
    }


    private String uuid() {
        return  UUID.randomUUID().toString().replaceAll("-", "");
    }

    private String type(MultipartFile file) {
        return Optional.ofNullable(file.getOriginalFilename())
                .filter(f -> f.contains("."))
                .map(f -> f.substring(f.lastIndexOf(".")).toLowerCase())
                .orElse("");
    }
}
